package abstractGA.chrom;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import algorithm.AlgCtx;
import algorithm.IAlgOperation;
import abstractGA.GAParameter;
import foundation.fileUtil.DataCell;

/**
 * 染色体类
 * 
 * @author nyc
 * 
 */
public abstract class Chrom implements IChromCodeChged {
	// 染色体编码
	protected List<StringBuffer> codes = new ArrayList<StringBuffer>();
	// 当前目标值
	protected List<StringBuffer> objVals = new ArrayList<>();
	// 染色体位变更事件处理对象
	protected IChromCodeChged listener = null;
	protected GAParameter para = null;
	// 产生随机数
	protected Random random = null;
	// 算法操作接口
	protected IAlgOperation  algOper = null;

	public Chrom() {

	}

	public Chrom(List<StringBuffer> codes) {
		this.codes = codes;
	}

	/**
	 * 构造函数
	 * 
	 * @param algCtx
	 *            ：算法运行上下文
	 * @param para
	 *            ：配置参数
	 */
	public Chrom(AlgCtx algCtx, GAParameter para) {
		algOper = algCtx.getAlgOper();
		listener = this;
		this.para = para;
		random = new Random();
		codes = getRndCodes();
	}

	

	/**
	 * @return：返回一个随机的染色体编码
	 */
	public List<StringBuffer> getRndCodes(){
		return algOper.getRndCodes();
	}

	/**
	 * @return:复制并返回一条新的染色体
	 */
	public abstract Chrom copy();

	/**
	 * 变异操作
	 * 
	 * @param mutateNum
	 *            :变异次数,目前仅考虑单点变异
	 */
	public  void mutate(int mutateNum){
		List<StringBuffer> newCodes=algOper.mutate(mutateNum,codes,random,para.getMutateProb());
		if(!algOper.isLegalCodes(newCodes)){
			newCodes=algOper.repairCodes(newCodes);		
		}
		setCodes(newCodes);
	}

	@Override
	/**
	 * 染色体编码变更事件处理
	 */
	public void onChromCodeChged(List<StringBuffer> oldCodes,
			List<StringBuffer> newCodes) {
		objVals.clear();
	}

	/**
	 * 获取目标值		
	 */
	public List<StringBuffer> getObjVals() {		
		//编码不合法，修复
//		if(!algOper.isLegalCodes(codes)){
//			codes=algOper.repairCodes(codes);		
//		}		
		// 判断是否已求解过目标值		
		if (objVals.size() ==0) {//目标值需要重新计算
			objVals=algOper.getObjVals(codes);			
		}		
		return objVals;
	}
	
	/**
	 * 判断两个染色体编码及对应的各目标值是否相同
	 * 
	 * @param tgtChrom
	 *            ：目标染色体
	 * @return:两个当前和目标染色体对应的编码及目标值相同返回真，否则返回假
	 */
//	public boolean isEqual(Chrom tgtChrom) {
//		boolean retVal = false;
//		//编码是否相同
//		boolean codesEqual = false;
//		List<StringBuffer> srcCodes = getCodes();
//		List<StringBuffer> targetCodes = tgtChrom.getCodes();
//		for(int i=0;i<srcCodes.size();i++){
//			if(srcCodes.get(i).toString().equals(targetCodes.get(i).toString())){
//				codesEqual = true;
//			}else{
//				codesEqual = false;
//				break;
//			}
//		}
//		
//		List<StringBuffer> srcObjVals = getObjVals();
//		List<StringBuffer> targetObjVals = tgtChrom.getObjVals();
//		float srcObjVal1 = ((Float) srcObjVals.get(0)).floatValue();
//		float srcObjVal2 = ((Float) srcObjVals.get(1)).floatValue();
//		float srcObjVal3 = ((Float) srcObjVals.get(2)).floatValue();
//
//		float targetObjVal1 = ((Float) targetObjVals.get(0)).floatValue();
//		float targetObjVal2 = ((Float) targetObjVals.get(1)).floatValue();
//		float targetObjVal3 = ((Float) targetObjVals.get(2)).floatValue();
//
//		boolean obj1IsEqual = Float.compare(srcObjVal1, targetObjVal1) == 0;
//		boolean obj2IsEqual = Float.compare(srcObjVal2, targetObjVal2) == 0;
//		boolean obj3IsEqual = Float.compare(srcObjVal3, targetObjVal3) == 0;
//		//目标值是否相同
//		boolean objEqual = obj1IsEqual && obj2IsEqual && obj3IsEqual;
//		//个体是否相同
//		if (codesEqual && objEqual) {
//			retVal = true;
//		}
//		return retVal;
//	}
	
	/**
	 * 获取当前染色体状态
	 * @return
	 */
	public int getChromState(){
		return 0;
		
	}

	public void setObjVals(ArrayList<StringBuffer> objVals) {
		this.objVals = objVals;
	}

	// 按[1,2,0,3,...]:fitness的格式输出染色体对应的字符串
	public String outChrom() {
		String chromStr = "[";
		int size = codes.size();
		for (int i = 0; i < size; i++) {
			String curCodeStr = codes.get(i).toString();
			chromStr += curCodeStr;
			if (i != size - 1) {
				chromStr += ",";
			}
		}
		chromStr += "]:";
		int j = 1;
		size = getObjVals().size();

		for (Object objVal : objVals) {
			if (j != size) {
				chromStr += "objVal" + j + "=" + objVal + ",";
			} else {
				chromStr += "objVal" + j + "=" + objVal + "\r";
			}
			j++;
		}

		return chromStr;
	}

	/**
	 * 按 population1 chrom1-[1,2,0,3,...]:fitness 格式输出
	 * 
	 * @param genNum
	 *            ：第几代种群
	 * @return
	 */
	public List<DataCell> outChrom(int genNum) {
		List<DataCell> chromRow = new ArrayList<DataCell>();
		DataCell titleCell = new DataCell();

		String cellContent = "bestChrom(" + String.valueOf(genNum) + ")--";
		cellContent += outChrom();
		titleCell.setName(cellContent);
		chromRow.add(titleCell);

		return chromRow;
	}

	public List<StringBuffer> getCodes() {
		return codes;
	}

	public void setCodes(List<StringBuffer> newCodes) {
		int size = codes.size();
		int newSize = newCodes.size();
		boolean isIdentical = true;
		if (size == newSize) {
			for (int i = 0; i < size; i++) {
				String code = codes.get(i).toString();
				String newCode = newCodes.get(i).toString();
				if (!code.equals(newCode)) {
					isIdentical = false;
					break;
				}
			}
		}
		if (!isIdentical) {
			objVals.clear();
			listener.onChromCodeChged(codes, newCodes);
			this.codes = newCodes;
		}
	}

	public IChromCodeChged getListener() {
		return listener;
	}

	public void setListener(IChromCodeChged listener) {
		this.listener = listener;
	}

	public GAParameter getPara() {
		return para;
	}

	public void setPara(GAParameter para) {
		this.para = para;
	}

	public Random getRandom() {
		return random;
	}

	public void setRandom(Random random) {
		this.random = random;
	}

	public IAlgOperation getAlgOper() {
		return algOper;
	}

	public void setAlgOper(IAlgOperation algOper) {
		this.algOper = algOper;
	}


}
